﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using Kaleida.ServiceMonitor.Framework;
using Kaleida.ServiceMonitor.Framework.Responses;

namespace Kaleida.ServiceMonitor.Operations.PreparedRequests
{
    public class Ping : PreparedRequest
    {
        private const string Data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
        private TimeSpan timeout;

        private readonly string hostNameOrAddress;

        public Ping(string hostNameOrAddress) : this(hostNameOrAddress, "50s")
        {
        }
        public Ping(string hostNameOrAddress, string timeout)
        {
            var timeoutTimeSpan = timeout.ToTimeSpan();

            if (timeoutTimeSpan.TotalMilliseconds < 1)
                throw new ArgumentOutOfRangeException("timeout", timeout, "Cannot be less than 1 millisecond");

            this.hostNameOrAddress = hostNameOrAddress;
            this.timeout = timeoutTimeSpan;
        }

        public override string Description
        {
            get { return string.Format("Determine if '{0}' is available using an ICMP request with a timeout of {1}ms", hostNameOrAddress, timeout.TotalMilliseconds); }
        }

        public override object GetResponse()
        {
            var pinger = new System.Net.NetworkInformation.Ping();
            byte[] buffer = Encoding.ASCII.GetBytes(Data);

            PingReply reply = pinger.Send(hostNameOrAddress, (int) timeout.TotalMilliseconds, buffer);
            if (reply == null)
                throw new InvalidOperationException("Ping reply was null");

            switch (reply.Status)
            {
                case IPStatus.Success:
                    return new PingResponse(reply.Status, TimeSpan.FromMilliseconds(reply.RoundtripTime));
                case IPStatus.TimedOut:
                    return new PingResponse(new PingTimedOutException(string.Format("Ping to {0} timed out", hostNameOrAddress)));
                default:
                    return new PingResponse(new InvalidOperationException(string.Format("Ping to {0} returned {1}", hostNameOrAddress, reply.Status)));
            }
        }

    }
}
